#include "window.hpp"
#include "findduplicates.hpp"
#include "daterestriction.hpp"
#include "sizerestriction.hpp"

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDir>
#include <QFileDialog>
#include <QMessageBox>
#include <QTreeView>
#include <QCalendarWidget>
#include <QStringList>

Window::Window(){
	setWindowTitle(tr("Hadu ~ I Hate Duplicates"));
	for(int i=0;i<4;i++)
		rest[i]=0;
	qllocation=new QLabel("Local");
	qlelocation=new QLineEdit(QDir::homePath());
	qpbbrowse=new QPushButton("Browse");
	
	QHBoxLayout *horizontallocation = new QHBoxLayout();
	horizontallocation->addWidget(qllocation);
	horizontallocation->addWidget(qlelocation);
	horizontallocation->addWidget(qpbbrowse);

	gbhorizontal=new QGroupBox(QString::fromUtf8("Restrições"));

	qvblrestrictions=new QVBoxLayout();
	qcbrestriction=new QComboBox();
	qcbrestriction->addItem(QString::fromUtf8("Data de modificação anterior a"));
	qcbrestriction->addItem(QString::fromUtf8("Data de modificação posterior a"));
	qcbrestriction->addItem("Tamanho maior que");
	qcbrestriction->addItem("Tamanho menor que");
	qpbaddrestriction=new QPushButton("Adiciona");
	connect(qpbaddrestriction,SIGNAL(clicked()),this,SLOT(addRestriction()));
	
	QHBoxLayout *horizontalrestriction = new QHBoxLayout();
	horizontalrestriction->addWidget(qcbrestriction);
	horizontalrestriction->addWidget(qpbaddrestriction);

	QVBoxLayout *verticalrestriction = new QVBoxLayout();
	verticalrestriction->addLayout(qvblrestrictions);
	verticalrestriction->addLayout(horizontalrestriction);

	gbhorizontal->setLayout(verticalrestriction);

	qpbstart=new QPushButton("Achar!");
	qpbstop=new QPushButton("Parar");
	qpbstop->setEnabled(false);
	
	QHBoxLayout *horizontalcontrol = new QHBoxLayout();
	horizontalcontrol->addWidget(qpbstart);
	horizontalcontrol->addWidget(qpbstop);
	
	qltype= new QLabel("Busca duplicatas com");
	qcbtype= new QComboBox();
	qcbtype->addItem("Nomes iguais");
	qcbtype->addItem(QString::fromUtf8("Extensões iguais"));
	qcbtype->addItem("Nada igual");
	
	qtw=new MyTree();
	qtw->setHeaderLabels(QStringList("Duplicatas"));
	qtw->setSelectionMode(QAbstractItemView::ExtendedSelection);
	
	QHBoxLayout *horizontalsearchtype= new QHBoxLayout();
	horizontalsearchtype->addWidget(qltype);
	horizontalsearchtype->addWidget(qcbtype);
	
	QVBoxLayout *verticalAll = new QVBoxLayout();
	verticalAll->addLayout(horizontallocation);
	verticalAll->addLayout(horizontalsearchtype);
	verticalAll->addWidget(gbhorizontal);
	verticalAll->addWidget(qtw);
	verticalAll->addLayout(horizontalcontrol);
	this->makeConnections();
	
	this->setLayout(verticalAll);
	resize(400,500);
}

Window::~Window(){
	for(int i=0;i<4;i++){
		if(!rest[i])
			delete rest[i];
	}
	if(!qtw)
		delete qtw;
	if(!qvblrestrictions)
		delete qvblrestrictions;
	if(!qllocation)
		delete qllocation;
	if(!qltype)
		delete qltype;
	if(!qpbbrowse)
		delete qpbbrowse;
	if(!qpbstart)
		delete qpbstart;
	if(!qpbstop)
		delete qpbstop;
	if(!qpbaddrestriction)
		delete qpbaddrestriction;
	if(!qlelocation)
		delete qlelocation;
	if(!qcbtype)
		delete qcbtype;
	if(!qcbrestriction)
		delete qcbrestriction;
	if(!wc)
		delete wc;
	if(!mut_ui)
		delete mut_ui;
	if(!mut_fl)
		delete mut_fl;
	if(!sem)
		delete sem;
	if(!qllocation)
		delete qllocation;
	if(!qpbbrowse)
		delete qpbbrowse;
	if(!qpbstart)
		delete qpbstart;
	if(!qpbstop)
		delete qpbstop;
	if(!qlelocation)
		delete qlelocation;
	if(!gbhorizontal)
		delete gbhorizontal;
}

void Window::addDuplicates(QList<QFileInfo *> *l){
	mut_ui->lock();
	if(l->size()==2){
		QString qst("Duplicatas "+QString::number(groups.size())+" "+QString::number(l->first()->size()));
		groups[l]=new QTreeWidgetItem(QStringList(qst));
		QTreeWidgetItem *newItemChild0=new QTreeWidgetItem(QStringList((l->value(0)->absoluteFilePath())));
		QTreeWidgetItem *newItemChild1=new QTreeWidgetItem(QStringList((l->value(1)->absoluteFilePath())));
		QList<QTreeWidgetItem *> qlist;
		qlist.append(newItemChild0);
		qlist.append(newItemChild1);
		groups[l]->addChildren(qlist);
		qtw->addTopLevelItem(groups[l]);
	}
	else{
		if(l->size()>=3)
			groups[l]->addChild(new QTreeWidgetItem(QStringList((l->last()->absoluteFilePath())))); //pega e tira o ultimo da lista
	}
	mut_ui->unlock();
	wc->wakeAll();
}

void Window::rmDuplicates(){
	QList<QTreeWidgetItem *> qlsi=qtw->selectedItems();
	for(QList<QTreeWidgetItem *>::iterator it=qlsi.begin();it!=qlsi.end();it++){
		if(qtw->indexOfTopLevelItem(*it)!=-1){
			if((*it)->childCount()>0){
				QString message="Deseja remover todos esses arquivos?\n\n";
				QList<QTreeWidgetItem *> children=(*it)->takeChildren();
				(*it)->addChildren(children);
				for(QList<QTreeWidgetItem *>::iterator it2=children.begin();it2!=children.end();it2++){
					message+=(*it2)->text(0)+"\n";
				}
				if(QMessageBox::question(this,"Remover Arquivos",message,QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes){
					QString forbiddenFiles=QString::fromUtf8("Não foi possível remover os arquivos:\n\n");
					for(QList<QTreeWidgetItem *>::iterator it2=children.begin();it2!=children.end();it2++){
						if(QFile::remove((*it2)->text(0))){
							qtw->removeItemWidget(*it2,0);
							delete *it2;
						}
						else{
							forbiddenFiles+=(*it2)->text(0)+'\n';
						}
					}
					if((*it)->childCount()==0){
						qtw->removeItemWidget(*it,0);
						delete *it;
					}
					else{
						QMessageBox::critical(this, "Erro!",forbiddenFiles+QString::fromUtf8("\nTalvez os arquivos ja tenham sido removidos ou você não tem permissão para fazê-lo."));
					}
				}
			}
			else{
				qtw->removeItemWidget(*it,0);
				delete *it;
			}
		}
		else{
			if(QMessageBox::question(this,"Remover Arquivo","Deseja remover esse arquivo?\n\n"+(*it)->text(0)+'\n',QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes){
				if(QFile::remove((*it)->text(0))){
					if((*it)->parent()->childCount()==2){
						qtw->removeItemWidget((*it)->parent(),0);
						delete (*it)->parent();
					}
					else{
						qtw->removeItemWidget(*it,0);
						delete *it;
					}
				}
				else
					QMessageBox::critical(this, "Erro!",QString::fromUtf8("Não foi possível remover o arquivo:\n\n")+(*it)->text(0)+QString::fromUtf8("\n\nTalvez o arquivo ja tenha sido removido ou você não tem permissão para fazê-lo."));
			}
		}
	}
}

void Window::addRestriction(){
	int type=this->qcbrestriction->currentIndex();
	QString text=qcbrestriction->currentText();
	this->qcbrestriction->removeItem(type);
	RestrictionLayout *rl;
	for(;;){
		if(text==QString::fromUtf8("Data de modificação anterior a")){
			type=0;
			rl=new DateRestriction(0);
			break;
		}
		if(text==QString::fromUtf8("Data de modificação posterior a")){
			type=1;
			rl=new DateRestriction(1);
			break;
		}
		if(text=="Tamanho maior que"){
			type=2;
			rl=new SizeRestriction(2);
			break;
		}
		if(text=="Tamanho menor que"){
			type=3;
			rl=new SizeRestriction(3);
			break;
		}
	}
	connect(rl,SIGNAL(remove(int)),this,SLOT(rmRestriction(int)));
	qvblrestrictions->addLayout(rl);
	rest[type]=rl;
	if(qcbrestriction->count()==0){
		qpbaddrestriction->setEnabled(false);
	}
}

void Window::rmRestriction(int type){
	QString qs=rest[type]->getName();
	delete rest[type];
	rest[type]=0;
	int i;
	bool broken=false;
	for(i=std::min(type,qcbrestriction->count());i>0;){
		if(qcbrestriction->itemText(--i)<qs){
			broken=true;
			break;
		}
	}
	qcbrestriction->insertItem(broken?i+1:i,qs);
	
	if(!qpbaddrestriction->isEnabled()){
		qpbaddrestriction->setEnabled(true);
	}
	qcbrestriction->setCurrentIndex(0);
	qcbrestriction->update();
}

void Window::browse(){
	QString qs=QFileDialog::getExistingDirectory(this,tr("Find Files"),qlelocation->displayText());
	if(qs!="")
		this->qlelocation->setText(qs);
}

void Window::findDuplicates(){
	if(this->validate()){
		qpbstop->disconnect(SIGNAL(clicked()));
		qpbstop->setText("Parar");
		qtw->clear();
		groups.clear();
		QDateTime maxDate=(rest[0]==0)?QDateTime():QDateTime((((DateRestriction*)(rest[0]))->getDate()),QTime(0,0));
		QDateTime minDate=(rest[1]==0)?QDateTime():QDateTime((((DateRestriction*)(rest[1]))->getDate()),QTime(23,59,59));
		if(!minDate.isValid())
			minDate=QDateTime();
		if(!maxDate.isValid())
			maxDate=QDateTime();
		qint64 minSize=(rest[2]==0)?-1:(((SizeRestriction*)(rest[2]))->getSize());
		qint64 maxSize=(rest[3]==0)?-1:(((SizeRestriction*)(rest[3]))->getSize());
		mut_ui=new QMutex();
		mut_fl=new QMutex();
		sem=new QSemaphore();
		wc=new QWaitCondition();
		files=new FilesList(qlelocation->text(),minDate,maxDate,minSize,maxSize,mut_fl,sem,this);
		t=new FindDuplicates(files,wc,mut_ui,mut_fl,sem,this);
		connect(t,SIGNAL(duplicate(QList<QFileInfo *> *)),this,SLOT(addDuplicates(QList<QFileInfo *> *)));
		connect(files,SIGNAL(finished()),t,SLOT(filesFinished()));
		connect(files,SIGNAL(terminated()),t,SLOT(filesFinished()));
		connect(t,SIGNAL(finished()),this,SLOT(threadFinished()));
		connect(t,SIGNAL(terminated()),this,SLOT(threadFinished()));
		connect(qpbstop,SIGNAL(clicked()),t,SLOT(stop()));
		qpbstop->setText("Parar");
		t->setOption(qcbtype->currentIndex());
		time=QDateTime::currentDateTime();
		t->start();
		this->qpbstart->setEnabled(false);
		this->qpbstop->setEnabled(true);
	}
}

void Window::threadFinished(){
	this->qpbstart->setEnabled(true);
	qpbstop->disconnect(SIGNAL(clicked()));
	uint timeseconds = (QDateTime::currentDateTime()).toTime_t() - time.toTime_t();
	QString hours = (((timeseconds/3600)<10)?QString::number(0):QString())+ QString::number(timeseconds/3600);
	QString minutes = ((((timeseconds%3600)/60)<10)?QString::number(0):QString())+QString::number((timeseconds%3600)/60);
	QString seconds = ((((timeseconds%3600)%60)<10)?QString::number(0):QString())+QString::number((timeseconds%3600)%60);
	QMessageBox::information(this, "Terminou!", "Tempo  "+hours+":"+minutes+":"+seconds);
	delete sem;
	delete wc;
	delete mut_ui;
	delete mut_fl;
	delete t;
	delete files;
	if(groups.size()>0){
		qpbstop->setText("Deletar");
		connect(qpbstop,SIGNAL(clicked()),this,SLOT(rmDuplicates()));
	}
	else
		this->qpbstop->setEnabled(false);

	QFile logFile(qlelocation->displayText()+"/hadu.log");
	logFile.remove();
	if(logFile.open(QIODevice::WriteOnly)){
		for(int i=0;qtw->topLevelItem(i);i++){
			QTreeWidgetItem *tl=qtw->topLevelItem(i);
			for(int i=0;i!=tl->childCount();i++){
				logFile.write((tl->child(i)->text(0)+'\n').toUtf8());
			}
			logFile.write("\n");
		}
	}

}

bool Window::validate(){
	QString errorMessage=this->validateLocation()+this->validateRestrictions();
	if(errorMessage!=""){
		QMessageBox::critical(this, "Erro!", errorMessage);
		return false;
	}
	return true;
}

QString Window::validateLocation(){
	QDir directory=QDir(qlelocation->displayText());
	if(!directory.exists()){
		return QString::fromUtf8("Selecione um local válido.\n");
	}
	return "";
}

QString Window::validateRestrictions(){
	QString errorMessage;
	QDateTime maxDate=(rest[0]==0)?QDateTime():QDateTime((((DateRestriction*)(rest[0]))->getDate()),QTime(0,0));
	QDateTime minDate=(rest[1]==0)?QDateTime():QDateTime((((DateRestriction*)(rest[1]))->getDate()),QTime(23,59,59));
	qint64 minSize=(rest[2]==0)?-1:(((SizeRestriction*)(rest[2]))->getSize());
	qint64 maxSize=(rest[3]==0)?-1:(((SizeRestriction*)(rest[3]))->getSize());
	if(rest[2]!=0){
		for(;;){
			if(((((SizeRestriction*)(rest[2]))->getLine()))->displayText()==""){
				errorMessage+=QString::fromUtf8("- O campo de restrição mínima de tamanho não foi preenchido.\n");
				break;
			}
			if(minSize<0)
				errorMessage+=QString::fromUtf8("- O tamanho mínimo deve ser maior ou igual 0.\n");
			break;
		}
	}
	if(rest[3]!=0){
		for(;;){
			if(((((SizeRestriction*)(rest[3]))->getLine()))->displayText()==""){
				errorMessage+=QString::fromUtf8("- O campo de restrição máxima de tamanho não foi preenchido.\n");
				break;
			}
			if(rest[3]!=0 && maxSize<=0)
				errorMessage+=QString::fromUtf8("- O tamanho máximo deve ser maior que 0.\n");
			break;
		}
	}
	if(rest[2]!=0 && rest[3]!=0 && maxSize<=minSize)
		errorMessage+=QString::fromUtf8("- O tamanho máximo deve ser maior que o tamanho mínimo.\n");
	if(rest[0]!=0 && rest[1]!=0 && minDate>maxDate)
		errorMessage+=QString::fromUtf8("- A data de modificação mínima é maior que a máxima.\n");
	return errorMessage;
}

void Window::makeConnections(){
	connect(qpbbrowse,SIGNAL(released()),this,SLOT(browse()));
	connect(qpbstart,SIGNAL(clicked()),this,SLOT(findDuplicates()));
	connect(qtw,SIGNAL(rm()),this,SLOT(rmDuplicates()));
}
